//对套接字的接口进行封装的文件
#pragma once
#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

using namespace std;

class Sock
{
public:
    //静态成员函数1:创建套接字
    static int Socket()
    {
        //使用协议家族:选择IPV4网络通信:AF_INET
        //套接字类型:流式套接: SOCK_STREAM
        //协议类型  :默认为0
        int sock = socket(AF_INET,SOCK_STREAM,0);
        if(sock<0)  //创建套接字失败,没必要往后执行了
        {
            cerr<<"socket errno"<<errno<<endl;
            exit(2);
        }
        return sock;//返回创建好的套接字
    }
    //静态成员函数2:绑定套接字
    static void Bind(int sock, uint16_t port)//要绑定的套接字是谁,端口号是多少
    {
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));//先对结构体清空
        local.sin_family = AF_INET;//协议家族
        local.sin_port = htons(port);//端口号 主机转网络
        local.sin_addr.s_addr = INADDR_ANY;//云服务器不建议绑定固定的IP地址

        //绑定
        if (bind(sock, (struct sockaddr *)&local, sizeof(local)) < 0)
        {
            cerr << "bind error!" << endl;
            exit(3);
        }
    }

    //静态成员函数3:设置套接字为监听状态
    static void Listen(int sock)    //要监听的套接字是谁
    {
        if (listen(sock, 5) < 0)
        {
            cerr << "listen error !" << endl;
            exit(4);
        }
    }

    //静态成员函数4:服务端从套接字获取链接
    static int Accept(int sock) //从哪个套接字获取连接
    {
        struct sockaddr_in peer;
        socklen_t len = sizeof(peer);
        //从sock套接字获取,对端的信息会被保存放在peer里面
        int fd = accept(sock, (struct sockaddr *)&peer, &len);
        if(fd >= 0) //获取连接成功
        {
            return fd;//返回新的文件描述符
        }
        return -1;
    }

    //静态成员函数5:客户端连接服务器
    //第二个,第三个参数表示要连接的服务器的相关属性信息
    static void Connect(int sock, std::string ip, uint16_t port)
    {
        struct sockaddr_in server;//要连接哪个服务器,填入对应的信息
        memset(&server, 0, sizeof(server));

        server.sin_family = AF_INET;//协议家族
        server.sin_port = htons(port);//主机转网络
        server.sin_addr.s_addr = inet_addr(ip.c_str());//字符串IP->整数IP

        //连接
        if(connect(sock, (struct sockaddr*)&server, sizeof(server)) == 0)
        {
            cout << "Connect Success!" << endl;
        }
        else
        {
            cout << "Connect Failed!" << endl;
            exit(5);
        }
    }
};